package com.fengye.common.utils;

import org.springframework.data.redis.core.*;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Component;

import jakarta.annotation.Resource;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * Redis工具类
 * @author fengye
 * @date 2019/12/10
 */
@Component
public class RedisUtils {

    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    /* 基础类型数据 操作 */

    /**
     * 设置键值对，如果键已存在，则覆盖其值
     *
     * @param key   键
     * @param value 值
     */
    public void set(String key, Object value) {
        ValueOperations<String, Object> operations = redisTemplate.opsForValue();
        operations.set(key, value);
    }

    /**
     * 设置键值对，并设置过期时间
     *
     * @param key      键
     * @param value    值
     * @param timeout  过期时间
     * @param timeUnit 过期时间单位
     */
    public void setEx(String key, Object value, long timeout, TimeUnit timeUnit) {
        ValueOperations<String, Object> operations = redisTemplate.opsForValue();
        operations.set(key, value, timeout, timeUnit);
    }

    /**
     * 设置键值对，并设置过期时间
     *
     * @param key      键
     * @param value    值
     * @param timeout  过期时间（单位：秒）
     */
    public void setEx(String key, Object value, long timeout) {
        setEx(key, value, timeout, TimeUnit.SECONDS);
    }

    /**
     * 设置键值对，如果键已存在，则不覆盖其值
     *
     * @param key      键
     * @param value    值
     * @param timeout  过期时间
     * @param timeUnit 过期时间单位
     */
    public void setIfAbsent(String key, Object value, long timeout, TimeUnit timeUnit) {
        ValueOperations<String, Object> operations = redisTemplate.opsForValue();
        operations.setIfAbsent(key, value);
        operations.setIfAbsent(key, value, timeout, timeUnit);
    }

    /**
     * 设置键值对，如果键已存在，则不覆盖其值
     *
     * @param key      键
     * @param value    值
     * @param timeout  过期时间（单位：秒）
     */
    public void setIfAbsent(String key, Object value, long timeout) {
        setIfAbsent(key, value, timeout, TimeUnit.SECONDS);
    }

    /**
     * 设置键值对，如果键已存在，则不覆盖其值，并设置过期时间，如果键不存在，则会创建一个新的键，并将其初始值设置为0，后再进行自增操作。
     *
     * @param key      键
     * @param delta    计数值
     */
    public Long increment(String key, long delta) {
        ValueOperations<String, Object> operations = redisTemplate.opsForValue();
        Long increment = operations.increment(key, delta);
        return increment;
    }

    /**
     * 获取指定键的值
     *
     * @param key 键
     * @return 值
     */
    public Object get(String key) {
        ValueOperations<String, Object> operations = redisTemplate.opsForValue();
        return operations.get(key);
    }

    /**
     * 删除指定键
     *
     * @param key 键
     * @return 删除成功返回true，否则返回false（如键不存在）
     */
    public Boolean delete(String key) {
        return redisTemplate.delete(key);
    }

    /**
     * 判断键是否存在
     *
     * @param key 键
     * @return 存在返回true，否则返回false
     */
    public Boolean exists(String key) {
        return redisTemplate.hasKey(key);
    }

    /**
     * 查找匹配的键值对
     *
     * @param pattern 匹配模式（如：`foo*`）
     * @return 符合条件的键列表
     */
    public Set<String> keys(String pattern) {
        return redisTemplate.keys(pattern);
    }

    /* Hash操作 */

    /**
     * 向哈希表中添加键值对
     *
     * @param key   哈希表键
     * @param hashKey   哈希键
     * @param value 哈希值
     */
    public void hPut(String key, String hashKey, Object value) {
        HashOperations<String, String, Object> hashOps = redisTemplate.opsForHash();
        hashOps.put(key, hashKey, value);
    }

    /**
     * 向哈希表中添加多个键值对
     * @param key 哈希表键
     * @param map 键值对
     */
    public void hPutAll(String key, Map<String, Object> map) {
        HashOperations<String, String, Object> hashOps = redisTemplate.opsForHash();
        hashOps.putAll(key, map);
    }

    /**
     * 从哈希表中获取指定哈希键的值
     *
     * @param key   哈希表键
     * @param hashKey   哈希键
     * @return 哈希值
     */
    public Object hGet(String key, String hashKey) {
        HashOperations<String, String, Object> hashOps = redisTemplate.opsForHash();
        return hashOps.get(key, hashKey);
    }

    /**
     * 从哈希表中获取所有键值对
     *
     * @param key   哈希表键
     * @return 哈希值
     */
    public Map<String, Object> hGetMap(String key) {
        HashOperations<String, String, Object> hashOps = redisTemplate.opsForHash();
        return hashOps.entries(key);
    }

    /**
     * 从哈希表中删除指定哈希键
     *
     * @param key   哈希表键
     * @param hashKey   哈希键
     */
    public void hDelete(String key, String hashKey) {
        HashOperations<String, String, Object> hashOps = redisTemplate.opsForHash();
        hashOps.delete(key, hashKey);
    }

    /**
     * 在哈希表中增加指定哈希键的值
     *
     * @param key   哈希表键
     * @param hashKey   哈希键
     * @param setpValue 增量值
     */
    public void hIncrement(String key, String hashKey, int setpValue) {
        HashOperations<String, String, Object> hashOps = redisTemplate.opsForHash();
        hashOps.increment(key, hashKey, setpValue);
    }

    /*  列表操作  */

    /**
     * 在列表左侧添加元素
     *
     * @param key   列表键
     * @param value 元素值
     */
    public void lPush(String key, Object value) {
        ListOperations<String, Object> listOps = redisTemplate.opsForList();
        listOps.leftPush(key, value);
    }

    /**
     * 在列表右侧添加元素
     *
     * @param key   列表键
     * @param value 元素值
     */
    public void rPush(String key, Object value) {
        ListOperations<String, Object> listOps = redisTemplate.opsForList();
        listOps.rightPush(key, value);
    }

    /**
     * 从列表左侧弹出元素
     *
     * @param key 列表键
     * @return 弹出的元素值，若列表为空则返回null
     */
    public Object lPop(String key) {
        ListOperations<String, Object> listOps = redisTemplate.opsForList();
        return listOps.leftPop(key);
    }

    /**
     * 从列表右侧弹出元素
     *
     * @param key 列表键
     * @return 弹出的元素值，若列表为空则返回null
     */
    public Object rPop(String key) {
        ListOperations<String, Object> listOps = redisTemplate.opsForList();
        return listOps.rightPop(key);
    }

    /**
     * 获取列表指定范围内的元素
     *
     * @param key   列表键
     * @param start 起始位置（0-based，包含）
     * @param end   结束位置（0-based，包含）
     * @return 指定范围内元素列表
     */
    public List<Object> lRange(String key, long start, long end) {
        ListOperations<String, Object> listOps = redisTemplate.opsForList();
        return listOps.range(key, start, end);
    }

    /* 集合操作 */

    /**
     * 添加元素到集合
     *
     * @param key   集合键
     * @param values 待添加元素集合
     * @return 实际添加到集合的新元素数量
     */
    public long sAdd(String key, Collection<Object> values) {
        SetOperations<String, Object> setOps = redisTemplate.opsForSet();
        return setOps.add(key, values.toArray());
    }

    /**
     * 判断集合中是否包含指定元素
     *
     * @param key   集合键
     * @param value 待查询元素
     * @return 若集合包含元素则返回true，否则返回false
     */
    public boolean sIsMember(String key, Object value) {
        SetOperations<String, Object> setOps = redisTemplate.opsForSet();
        return setOps.isMember(key, value);
    }

    /**
     * 从集合中移除指定元素
     *
     * @param key   集合键
     * @param values 待移除元素集合
     * @return 实际从集合中移除的元素数量
     */
    public Long sRemove(String key, Object... values) {
        SetOperations<String, Object> setOps = redisTemplate.opsForSet();
        return setOps.remove(key, values);
    }

    /**
     * 获取集合所有元素
     *
     * @param key 集合键
     * @return 集合元素集合
     */
    public Set<Object> sMembers(String key) {
        SetOperations<String, Object> setOps = redisTemplate.opsForSet();
        return setOps.members(key);
    }

    /*  有序集合操作 */

    /**
     * 向有序集合中添加成员，同时指定分数
     *
     * @param key   有序集合键
     * @param member 成员
     * @param score 分数
     */
    public void zAdd(String key, double score, Object member) {
        ZSetOperations<String, Object> zSetOps = redisTemplate.opsForZSet();
        zSetOps.add(key, member, score);
    }

    /**
     * 获取有序集合中指定成员的分数
     *
     * @param key   有序集合键
     * @param member 成员
     * @return 分数，若成员不存在则返回null
     */
    public Double zScore(String key, Object member) {
        ZSetOperations<String, Object> zSetOps = redisTemplate.opsForZSet();
        return zSetOps.score(key, member);
    }

    /**
     * 移除有序集合中的指定成员
     *
     * @param key   有序集合键
     * @param members 待移除成员集合
     * @return 实际移除的成员数量
     */
    public Long zRemove(String key, Object... members) {
        ZSetOperations<String, Object> zSetOps = redisTemplate.opsForZSet();
        return zSetOps.remove(key, members);
    }

    /**
     * 获取有序集合中指定范围的成员，按分数排序
     *
     * @param key   有序集合键
     * @param start 起始位置（0-based，包含）
     * @param end   结束位置（0-based，包含）
     * @return 指定范围内的成员集合
     */
    public Set<Object> zRange(String key, long start, long end) {
        ZSetOperations<String, Object> zSetOps = redisTemplate.opsForZSet();
        return zSetOps.range(key, start, end);
    }

    /**
     * 设置键的过期时间
     *
     * @param key  键
     * @param timeout 过期时间
     * @param unit 时间单位
     * @return 若键存在则返回true，否则返回false
     */
    public Boolean expire(String key, final long timeout, final TimeUnit unit) {
        return redisTemplate.expire(key, timeout, unit);
    }
}
